package cn.hyatt.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * (高德墨卡托)墨卡托坐标实用程序
 *
 * @author hyatt
 */
public class MercatorCoordinateUtil {
    // 参考点的经度
    private static final BigDecimal LONGITUDE_OFFSET = BigDecimal.valueOf(0);
    // 参考点的纬度
    private static final BigDecimal LATITUDE_OFFSET = BigDecimal.valueOf(0);
    // 参考点的x轴
    private static final Integer X_OFFSET = 0;
    // 参考点的y轴
    private static final Integer Y_OFFSET = 0;
    // 自定义坐标系的单位 - 厘米
    private static final Integer CONVERSION_UNIT = 1;
    // 一度 对应距离
    private static final Integer CORRESPONDING_DISTANCE = 11100000;
    // 地球半径（单位：千米）
    private static final Integer EARTH_RADIUS = 6371;


    /**
     * 将 X轴 转换为 精度范围
     *
     * @param x X轴 坐标
     * @return 精度
     */
    public static BigDecimal convertXToLon(Integer x) {
        return BigDecimal.valueOf(x - X_OFFSET).setScale(8, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(CONVERSION_UNIT))
                .divide(BigDecimal.valueOf(CORRESPONDING_DISTANCE), 8, RoundingMode.HALF_UP)
                .add(LONGITUDE_OFFSET);
    }

    /**
     * 将 Y轴 转换为 纬度范围
     *
     * @param y Y轴 坐标
     * @return 纬度
     */
    public static BigDecimal convertYToLat(Integer y) {
        return BigDecimal.valueOf(y - Y_OFFSET).setScale(8, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(CONVERSION_UNIT))
                .divide(BigDecimal.valueOf(CORRESPONDING_DISTANCE), 8, RoundingMode.HALF_UP)
                .add(LATITUDE_OFFSET);
    }

    /**
     * 计算距离 - 返回距离长度 （单位：千米）
     *
     * @param lon1 经度坐标1
     * @param lat1 纬度坐标1
     * @param lon2 经度坐标2
     * @param lat2 纬度坐标2
     * @return 结果
     */
    public static BigDecimal calculateDistance(BigDecimal lon1, BigDecimal lat1, BigDecimal lon2, BigDecimal lat2) {
        // 将经纬度转换为弧度
        double radLat1 = Math.toRadians(lat1.doubleValue());
        double radLat2 = Math.toRadians(lat2.doubleValue());
        double radLon1 = Math.toRadians(lon1.doubleValue());
        double radLon2 = Math.toRadians(lon2.doubleValue());

        // Haversine 公式计算
        double a = radLat1 - radLat2;
        double b = radLon1 - radLon2;

        double s = 2 * Math.asin(
                Math.sqrt(
                        Math.pow(Math.sin(a / 2), 2)
                                + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)
                )
        );
        return BigDecimal.valueOf(s * EARTH_RADIUS).setScale(8, RoundingMode.HALF_UP);
    }

}
